// 来自paas，目前是用于产品类型质保规则的计算公式，没有替换原先公共组件，后续有需要可以替换改造

/* class */
import ValidateResult from '../BaseCalculationFormula/ValidateResult';
/* components */
import draggable from 'vuedraggable';
/* enum */
import { SignOperatorEnum, FormulaFuncTipEum, CalculationFormulaItem, SignOperators } from './formulaEnum';
/* util */
import {validate, validateType} from './validate';
import * as _ from 'lodash';
import i18n from '@src/locales';
/* vue */
import { Vue, Component, Prop, Emit } from 'vue-property-decorator';
import { CreateElement } from 'vue';
/* scss */
import './BaseCalculationFormula.scss';

//@ts-ignore
import { codemirror } from 'vue-codemirror';
import 'codemirror/lib/codemirror.css';
import './model.js'
import 'codemirror/addon/display/autorefresh.js';

import "codemirror/addon/edit/matchbrackets.js";
import "codemirror/addon/edit/closebrackets.js";
import "codemirror/addon/hint/show-hint.js";
import "codemirror/addon/hint/show-hint.css";

type FormulaFuncTipType = keyof typeof FormulaFuncTipEum

@Component({
  name: 'base-calculation-formula-new',
  components: { draggable, codemirror }
})
export default class BaseCalculationFormula extends Vue {
  /* 支持运算的字段列表 */
  @Prop({ default: [] }) calculationFields: Array<any> | undefined;

  /* 所有表单字段 */
  @Prop({ default: [] }) fields: Array<any> | undefined;

  /* 需要的计算函数 */
  @Prop({ default: [] }) formulaFuncFilter: Array<FormulaFuncTipType> | undefined;

  @Prop({ default: '' }) source: String | undefined;

  /* 计算公式数组 */
  private calculationFormula: CalculationFormulaItem[] = [];
  /* 默认数值 用来代替字段名字 */
  private defaultNumber: number | string = 0;
  /* 错误提示 */
  private errorMessage = '';
  /* 错误提示 */
  private selectedFormulaFunItem: FormulaFuncTipType = 'ADD';
  /* 计算公式符号列表 (暂不支持自定义，所以先写死了) */
  private operatorList: SignOperatorEnum[] = SignOperators;

  private formulaFuncList = Object.keys(FormulaFuncTipEum) as FormulaFuncTipType[];

  /* 显示状态 */
  private show = false;

  /* 输入框的内容 */
  private initVal = '';

  /* 输入框是否报错了 */
  private inputError = false;

  static install: (Vue: any) => void;

  /* 扁平化的计算公式数组 */
  get calculationFormulaFlat(): string[] {
    return this.calculationFormula.map(
      (item: CalculationFormulaItem) => item.value
    );
  }

  /**
   * @description 格式化的计算公式字符串
   */
  get calculationFormulaFormatted() {
    return this.calculationFormula
      .map((item: CalculationFormulaItem) =>
      {
        // 除了+ - * / () , 剩下都按照计算的值去处理
        // 不知道为什么有时候item.value会是'()'，然后就被转为field，所以加了个'()'~
         return this.formulaFuncList.includes(item.value) ? 'fun' : ([...this.operatorList, ',', '()'].includes(item.value)) ?  item.value : 'field'
      }
      )
      .join('');
  }

  get formulaFuncListFilter() {
    return this.formulaFuncList.filter(v => this.formulaFuncFilter?.includes(v));
  }

  /**
   * @description 取消
   */
  private cancel(): void {
    this.show = false;
  }

  @Emit('confirm')
  private saveFormula(data: any) {
    return _.cloneDeep(data);
  }

  /**
   * @description 确定
   */
  private confirm(): void {

    this.$nextTick(() => {
      // 判断是否存在已删除的无效字段
      let invalidFields = this.calculationFormula.filter(item => item.isDelete);
      if (invalidFields.length) {
        this.errorMessage = i18n.t('common.form.preview.forMula.tip1') as string;
        return;
      }

      // 判断输入框是否有error
      if(this.inputError) {
        this.errorMessage = i18n.t('common.form.preview.forMula.tip2') as string;
        return;
      }
      
      // 基础校验
      let result = validate(this.calculationFormulaFormatted, this.defaultNumber);
      let result2
      // 校验2目前是主要针对质保规则的校验，是在基础校验的基础上再进行校验，如果基础校验没通过，2也没必要校验，不然会有问题~
      if(result.isSuccess) result2 = validateType(this.calculationFormula, ['mustOneTime', 'minMaxSameType']);
      let isSuccess = result.isSuccess && result2?.isSuccess;

      // 清空错误信息
      this.handleClearErrorMessage();
      // // 失败
      if (!isSuccess) {
        return this.setErrorMessage(!result.isSuccess ? result : result2);
      }
      this.saveFormula(this.calculationFormula);
      this.show = false;
    });

  }

  /**
   * 描述 自定义获取输入框内容根据dom获取
   * @date 2022-06-12
   * @returns {any}
   */
  private getCalculationFormulaInputValue() {
    let rsArr = [];
    //@ts-ignore
    const wrapDoms = this.$refs.codemirror.codemirror.getScrollerElement();
    const allLinesDom = wrapDoms.getElementsByClassName('CodeMirror-line');
    for(let i = 0; i < allLinesDom.length; i++) {
      const node = allLinesDom[i];
      for(let j = 0 ; j < node.childNodes[0].childNodes.length; j++) {
        const contentNode = node.childNodes[0].childNodes[j];
        if(contentNode.classList && contentNode.classList.contains('CodeMirror-widget')) {
          const markDom = contentNode.childNodes[0];
          // 获取自定义的marker attribute
          const fieldName = markDom.getAttribute('data-id');
          const fieldItem = this.calculationFields && this.calculationFields.find(field => field.fieldName.includes(fieldName));
          // 获取内容
          const text = markDom.innerHTML;

          // formula数据结构
          const beGenCalculationFormulaItemObj = {
            fieldName,
            value: text,
            formType: fieldItem ? fieldItem.formType : '',
            valueLanguage: fieldItem ? fieldItem.displayNameLanguage : {},
            parentFieldName: fieldItem ? fieldItem.parentFieldName : '',
            isDelete: !fieldItem,
            tableName: fieldItem ? fieldItem.tableName : ''
          };

          rsArr.push(this.genCalculationFormulaItem(beGenCalculationFormulaItemObj));

        } else {
          if(contentNode.classList && contentNode.classList.contains('cm-error')) {
            this.inputError = true;
            break;
          } else {
            this.inputError = false;
            if(this.initVal) {
              rsArr.push(this.genCalculationFormulaItem({ fieldName: '', value: contentNode.innerHTML, parentFieldName: '', isDelete: false}));
            }
          }
        }
      }
    }
    return rsArr;
  }

  /**
   * @description 操作符号点击
   * @param {SignOperatorEnum} operator 操作符
   */
  private handleOperatorClick(operator: SignOperatorEnum): void {
    this.insert(this.genCalculationFormulaItem({displayName: operator}), false);
  }

  /**
   * @description 运算字段点击
   * @param displayName
   * @param fieldName
   */
  private handleFieldClick(displayName: string, fieldName: string, formType: string): void {
    this.insert(this.genCalculationFormulaItem({displayName, fieldName, formType}));
  }

  /**
   * @description 显示，父组件有调用
   */
  private open(formula: []): void {

    this.calculationFormula = _.cloneDeep(formula);
    this.errorMessage = '';
    this.show = true;
    this.$nextTick(()=> {

      const { codemirror } = this.$refs.codemirror as any;
      codemirror.setValue('');

      formula.forEach((item: CalculationFormulaItem)=> {
        if(item.fieldName) {
          this.insert(this.genCalculationFormulaItem({ displayName: item.value as string, fieldName: item.fieldName, isDelete: item.isDelete }));
        } else {
          this.insert(this.genCalculationFormulaItem({ displayName: item.value }), false);
        }
      });

      setTimeout(()=> codemirror.refresh(), 0);
    });
  }

  /**
   * 描述 输入框的内容change时间
   * @date 2022-06-12
   * @returns {any}
   */
  private handleCodemirrorChange() {
    setTimeout(() => {
      this.calculationFormula = this.getCalculationFormulaInputValue();
      this.handleClearErrorMessage();
    }, 0);
  }

  /**
   * 描述 重置相关输入框中错误信息
   * @date 2022-06-12
   * @returns {any}
   */
  private handleClearErrorMessage() {
    this.calculationFormula.map(item => (item.isError = false));
    this.errorMessage = '';
  }


  /**
   * @description 设置错误信息数据
   */
  private setErrorMessage(validate: ValidateResult): void {
    let { errorMessage } = validate;

    // 错误提示
    this.errorMessage = errorMessage || '';
  }

  /**
   * 描述 相关插入框操作
   * @date 2022-06-10
   * @param {any} row:Record<string
   * @param {any} string>
   * @param {any} isRearm=true 是否是field
   * @param {any} isClickInsertAndFun=false 是否是函数插入
   * @returns {any}
   */
  insert(row: CalculationFormulaItem, isRearm = true, isClickInsertAndFun = false) {
    const { codemirror } = this.$refs.codemirror as any;
    //获取codemirror光标位置
    const pos = codemirror.getCursor();
    const insertPos = {
      line: pos.line,
      ch: pos.ch
    };

    const content = row.displayName;

    //制作标签dom(颜色样式自行设置)
    if(isRearm) {
      const dom = document.createElement("span");
      dom.className = "cm-field calculation-formula-tag mg-0";
      if(row.isDelete) {
        dom.className += " delete";
      }
      dom.setAttribute('data-id', row.fieldName);
      dom.innerHTML = content;
      const endPos = { line: insertPos.line, ch: insertPos.ch + content.length };
      codemirror.replaceRange(content, insertPos);//先插入字符串
      //再对插入字符串进行标签制定（其实就是在codemirror中动态添加标签）
      codemirror.markText(insertPos, endPos, {
        replacedWith: dom
      });
    } else {
      codemirror.replaceRange(content, insertPos);
    }
    codemirror.focus();
    isClickInsertAndFun && codemirror.setCursor({ line: insertPos.line, ch: insertPos.ch + content.length - 1 });

    this.initVal = codemirror.getValue();//获取codemirror内容
  }

  /**
   * 描述 生成CalculationFormulaItem object
   * @date 2022-06-13
   * @param {any} {fieldName=''
   * @param {any} parentFieldName=''
   * @param {any} formType=''
   * @param {any} displayName=''
   * @param {any} value=''
   * @param {any} isOperator=false
   * @param {any} isDelete=false
   * @param {any} isError=false}={}
   * @returns {any}
   */
  private genCalculationFormulaItem({
    fieldName = '',
    parentFieldName ='',
    formType = '',
    displayName = '',
    value = '',
    valueLanguage = {},
    isOperator = false,
    isDelete = false,
    isError = false,
    tableName = ''
  } = {}) {
    return {
      fieldName,
      parentFieldName,
      formType,
      displayName,
      value,
      valueLanguage,
      isOperator,
      isDelete,
      isError,
      tableName
    };
  }

  /**
   * @description 渲染运算符号列表
   */
  private renderOperator() {
    return (
      <div class="calculation-formula-operators">
        {i18n.t('common.form.preview.forMula.label1')}:
        {this.operatorList.map((operator: SignOperatorEnum) => {
          return (
            <span class="calculation-formula-tag" onClick={() => this.handleOperatorClick(operator)}>
              {operator}
            </span>
          );
        })}
      </div>
    );
  }

  /**
   * 描述 渲染相关组件列表
   * @date 2022-06-12
   * @returns {any}
   */
  private renderField() {
    return (
      <div class="calculation-formula-mid__box calculation-formula-fields">
        <div class="calculation-formula-mid_title align-items-center">
          <el-tooltip placement="top">
            <div slot="content">
              {i18n.t('common.form.preview.forMula.qualityTip')}
            </div>
            <i class="iconfont icon-question"></i>
          </el-tooltip>
          {i18n.t('common.form.preview.forMula.formOperand')}：
        </div>
        <div class="check-list">
          {this.calculationFields &&
              this.calculationFields.map(({ displayName, fieldName, formType, tableName }) => {
                return (
                  <div class="check-list-item">
                    { displayName.length > 6
                      ? (
                        <el-tooltip effect="dark" content={displayName} placement="top">
                          <span
                            class="calculation-formula-tag"
                            onClick={() => this.handleFieldClick(displayName, fieldName, formType)}
                          >
                            {displayName}
                          </span>
                        </el-tooltip>
                      )
                      : (
                        <span
                          class="calculation-formula-tag"
                          onClick={() => this.handleFieldClick(displayName, fieldName, formType)}
                        >
                          {displayName}
                        </span>
                      )}

                    { this.source === 'productQualityRule' &&
                      <el-tag>{tableName === 'product' ? i18n.t('common.base.product') : i18n.t('common.base.productType')}</el-tag>
                    }
                    {/* 质保这边暂时不需要子表单~ */}
                    {/* { isChildForm
                      ?  (
                        <el-tooltip effect="dark" content={`${i18n.t('common.form.type.subForm')}-${this.orderFieldNameFindDisplayName(parentFieldName)}`} placement="top">
                          <el-tag>{i18n.t('common.form.type.subForm')}</el-tag>
                        </el-tooltip>
                      )
                      :
                      <el-tag>{i18n.t('common.form.preview.forMula.parentForm')}</el-tag>
                    } */}
                  </div>
                );
              })}
        </div>
      </div>
    );
  }

  /**
   * 描述 渲染相关函数列表
   * @date 2022-06-12
   * @returns {any}
   */
  private renderFormulaFunc() {
    return (
      <div class="calculation-formula-mid__box calculation-formula-func">
        <div class="calculation-formula-mid_title align-items-center">
          {i18n.t('common.form.preview.forMula.operatingFunction')}：
        </div>
        <div class="check-list">
          {this.formulaFuncListFilter &&
              this.formulaFuncListFilter.map((item,  index) => {
                return (
                  <div class="check-list-item" key={index}>
                    <span
                      class="calculation-formula-tag"
                      onClick={()=> this.insert(this.genCalculationFormulaItem({displayName: `${item}()`}), false, true)}
                      onMouseenter={() => this.selectedFormulaFunItem = item as FormulaFuncTipType}
                    >
                      {item}
                    </span>
                  </div>
                );
              })}
        </div>
      </div>
    );
  }

  /**
   * 描述 渲染相关函数介绍
   * @date 2022-06-12
   * @returns {any}
   */
  private renderFormulaFuncIntro() {
    return (
      <div class="calculation-formula-mid__box  calculation-formula-intro"
        {...{
          domProps: {
            innerHTML: FormulaFuncTipEum[this.selectedFormulaFunItem]
          }
        }}>
      </div>
    );
  }

  /**
   * 描述 渲染相关弹窗中间部分
   * @date 2022-06-12
   * @returns {any}
   */
  private renderMidLayout() {
    return (
      <div class="calculation-formula-mid">
        {this.renderField()}
        {this.renderFormulaFunc()}
        {this.renderFormulaFuncIntro()}
      </div>
    );
  }

  /**
   * @description 渲染计算公式
   */
  private renderCalculationFormula() {
    return (
      <div class="calculation-formula-block">
        <div class="calculation-formula-title">{i18n.t('common.form.type.formula')}=</div>
        <div class="calculation-formula-content">
          {this.show && (
            <codemirror
              vModel={this.initVal}
              ref="codemirror"
              class="codemirror-edit"
              onChanges={()=> this.handleCodemirrorChange()}
              options={{
                lineWrapping: true,
                autoCloseBrackets: true,
                tabSize: 4,
                styleActiveLine: true,
                lineNumbers: true,
                matchBrackets: true,
                line: true,
                autoRefresh: true,
                extraKeys: { "Alt-/": "autocomplete" },
                mode: 'text/c-formula',
                hintOptions: {
                  completeSingle: false,
                },
                gutters: [
                  "CodeMirror-linenumbers",
                  "CodeMirror-foldgutter",
                  "CodeMirror-lint-markers", // CodeMirror-lint-markers是实现语法报错功能
                ],
              }}
            />
          )}
        </div>
      </div>
    );
  }

  /**
   * @description 渲染计算公式错误提示
   */
  private renderErrorMessage() {
    return (
      this.errorMessage && (
        <div class="calculation-formula-error">{this.errorMessage}</div>
      )
    );
  }

  render(h: CreateElement) {
    const attrs = {
      class: 'calculation-formula-modal-special',
      props: {
        show: this.show,
        title: i18n.t('common.form.tip.forMula.tips6'),
      },
      on: {
        'update:show': (val: boolean) => {
          this.show = val;
        }
      }
    };

    return (
      <base-modal {...attrs}>
        {this.renderCalculationFormula()}
        {this.renderErrorMessage()}
        {this.renderMidLayout()}
        {this.renderOperator()}
        <div slot="footer" class="dialog-footer">
          <el-button type="ghost" onClick={this.cancel}>
            {i18n.t('common.base.cancel')}
          </el-button>
          <el-button type="primary" onClick={this.confirm}>
            {i18n.t('common.base.save')}
          </el-button>
        </div>
      </base-modal>
    );
  }
}
